#pragma once
#include<iostream>
#include<string>
#include<cstring>
#include"Log.hpp"
#include<sys/types.h>
#include<sys/socket.h>
#include<cstring>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace LogModule;  //需要用到日志来完成一些操作

const int deafulet = -1;

class UdpServer
{
public:
    UdpServer(std :: string ip,int port,int socket1 = deafulet)  //缺省参数从右往左给
    :_socket(socket1),
    _ip(ip),
    _port(port),
    _isrunning(false)
    {}
    
    //服务器的启动工作
    void Init()
    {
        _socket = socket(AF_INET,SOCK_DGRAM,0);
        if(_socket < 0)
        {
            LOG(LogLeval :: FATAL) << "socket failed";
            exit(2);
        }
        LOG(LogLeval :: INFO) << "socket succeed";

        struct sockaddr_in local;  //定义一个结构体2，这个结构体里面存放了很多的东西

        memset(&local,0,sizeof(local));  //对于这个结构体，先把里面清理一下，避免出现某些错误结果


        local.sin_family = AF_INET;  //这个代表的是地址族，其实也说明了这个IPV4

        local.sin_port = htons(_port);  //强制转换为字符串类型

        //还有个ip

        local.sin_addr.s_addr =  inet_addr(_ip.c_str()); //直接转换完成

        //把套接字和结构体链接起来

        int n = bind(_socket,(sockaddr*)&local,sizeof(local));

        if(n < 0)
        {
            LOG(LogLeval::FATAL) << "bind failed";
            exit(2);
        }
        LOG(LogLeval::INFO) << "bind succeed";
    }


    //运行服务器，直接启动
    void Start()
    {
        _isrunning = true; //把服务器运行起来
        //进入死循环
        while(_isrunning)
        {
            //收到消息
            char buffer[1024];
            struct sockaddr_in _peer;  //定义一个结构体，当做之后函数的输出型参数
            socklen_t len = sizeof(_peer); //记录结构体的大小
            {
                ssize_t n = recvfrom(_socket,buffer,sizeof(buffer) - 1,0,(sockaddr*)&_peer,&len);
                if(n > 0)  //这代表信息手机成功了
                {
                    buffer[n] = 0; //不要忘记C语言的特性，必须要有\0
                    LOG(LogLeval :: DEBUG) << buffer;
                    //2.发送消息
                    sendto(_socket,buffer,sizeof(buffer),0,(sockaddr*)&_peer,len);
                }
            }
        }
    }

private:
    int _socket;  //套接字
    std :: string _ip;  //IP地址
    int _port; //端口号
    bool _isrunning; //判断服务器是否在运行
};